home *** CD-ROM | disk | FTP | other *** search
/ Nautilus 1992 July / Nautilus-3-8 / Nautilus-3-8.bin / Tools & Utilities / Techy Stuff / Source ƒ / Filelist ƒ / Search.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-09-14  |  21.1 KB  |  925 lines

  1. /*
  2.     FileList 1.4
  3.     "Search.c"
  4. */
  5.  
  6. #include "FileSearch.h"
  7. #include "Main.h"
  8. #include "Stack.h"
  9. #include "Utilities.h"
  10. #include "Window.h"
  11. #include "Search.h"
  12.  
  13. #define DeleteDialog        134        /* Delete? */
  14. #define        DeleteOk    1
  15. #define        DeleteNo    2
  16.  
  17. #define RenameDialog        135        /* Rename volume */
  18. #define        RenameOk    1
  19. #define        RenameNo    2
  20. #define        RenameRepl    3            /* Replace */
  21. #define        RenameOld    4            /* Old volume name */
  22. #define        RenameNew    5            /* New volume name */
  23.  
  24. #define    FindDialogF            136        /* Find (file) */
  25. #define FindDialogV            137        /* Find (volume) */
  26. #define        FindOk        1
  27. #define        FindNo        2
  28. #define        FindStr        3            /* String to find */
  29. #define        FindEqual    4            /* Exactly equal */
  30. #define        FindBegin    5            /* Match beginning */
  31. #define        FindInclude    6            /* Match somewhere */
  32. #define        FindEnd        7            /* Match end */
  33. #define        FindType    8            /* File type */
  34. #define        FindCreator    9            /* File creator */
  35.  
  36. #define    NOTHING    0xFFFFFFFF
  37.  
  38. /* ----- Dispose memory blocks ----------------------------------------- */
  39.  
  40. void DisposeMemory (void)
  41. {
  42.     FileData.max = VolumeData.max = InfoMax = 0;
  43.     if (InfoBase)
  44.         DisposPtr(InfoBase);
  45. }
  46.  
  47. /* ----- Allocate memory blocks ---------------------------------------- */
  48.  
  49. short NewMemory (
  50.     unsigned long program,    /* Minimum memory needed by program */
  51.     unsigned short files,    /* Percentage of files expected */
  52.     unsigned short volumes,    /* Percentage of volumes expected */
  53.     unsigned short record)    /* Average name size */
  54. {
  55.     register long x, y;
  56.     long grow;
  57.  
  58.     Heap = program;
  59.     Record = record;
  60.     record += sizeof(FileInfo) + 1;
  61.     record *= 100;
  62.     VolumeData.percent = volumes;
  63.     FileData.percent = files;
  64.     x = MaxMem(&grow);        /* Compact heap, purge everything */
  65.     x -= program;            /* Memory available for data storage */
  66.     if (x <= 0 || !(InfoBase = NewPtr(x)))
  67.         goto err;
  68.     y = (volumes + files) * sizeof(long) + record;
  69.     VolumeData.max = (volumes * x)/y;
  70.     FileData.max = (files * x)/y;
  71.     if ((VolumeData.base =
  72.             (long *)InfoBase + x/sizeof(long) - VolumeData.max)
  73.             <= (long *)InfoBase)
  74.         goto err;
  75.     if ((FileData.base = VolumeData.base - FileData.max)
  76.             <= (long *)InfoBase)
  77.         goto err;
  78.     InfoMax = (Ptr)FileData.base - InfoBase;
  79.     return 0;
  80. err:
  81.     DisposeMemory();
  82.     return 1;
  83. }
  84.  
  85. /* ----- Convert short to unsigned long -------------------------------- */
  86.  
  87. static unsigned long int2long (register unsigned short x)
  88. {
  89.     return (unsigned long)x;
  90. }
  91.  
  92. /* ----- Return record address ----------------------------------------- */
  93.  
  94. FileInfoPtr Address (
  95.     register WindowDataPtr w,
  96.     register long i)
  97. {
  98.     return (FileInfoPtr)(InfoBase + ((w->base)[i] & 0x7FFFFFFF));
  99. }
  100.  
  101. /* ----- Select record ------------------------------------------------- */
  102.  
  103. void Select (
  104.     register WindowDataPtr w,
  105.     register long i,
  106.     register Boolean sel)
  107. {
  108.     w->select = sel ? i : NOTHING;
  109. }
  110.  
  111. /* ----- Toggle record selection --------------------------------------- */
  112.  
  113. void Toggle (
  114.     register WindowDataPtr w,
  115.     register long i)
  116. {
  117.     Select(w, i, w->select == NOTHING);
  118. }
  119.  
  120. /* ----- Check if record is selected ----------------------------------- */
  121.  
  122. Boolean Selected (
  123.     register WindowDataPtr w,
  124.     register long i)
  125. {
  126.     return w->select == i;
  127. }
  128.  
  129. /* ----- Return volume name -------------------------------------------- */
  130.  
  131. Byte *GetVolume (register FileInfoPtr p)
  132. {
  133.     p = (FileInfoPtr)(InfoBase + p->volume);
  134.     return (Byte *)(&p->name);
  135. }
  136.  
  137. /* ----- Find path ----------------------------------------------------- */
  138.  
  139. void InitPath (
  140.     register FileInfoPtr p,
  141.     register STACK *stack)
  142. {
  143.     register short i;
  144.  
  145.     InitStack(stack);
  146.     while (p->kind != VOLUME && PushStack(stack, p->parent))
  147.         p = (FileInfoPtr)(InfoBase + p->parent);
  148. }
  149.  
  150. Byte *NextPath (register STACK *stack)
  151. {
  152.     register FileInfoPtr p;
  153.     register unsigned long x;
  154.  
  155.     if ((x = PopStack(stack)) == STACKERROR)
  156.         return 0;
  157.     p = (FileInfoPtr)(InfoBase + x);
  158.     return (Byte *)(&p->name);
  159. }
  160.  
  161. /* ----- Accept new file record ---------------------------------------- */
  162.  
  163. static short NewFile (unsigned long adr)
  164. {
  165.     if (FileData.count >= FileData.max)
  166.         return 1;
  167.     (FileData.base)[FileData.count] = adr;
  168.     FileData.count++;
  169.     return 0;
  170. }
  171.  
  172. /* ----- Accept new volume record -------------------------------------- */
  173.  
  174. static short NewVolume (unsigned long adr)
  175. {
  176.     if (VolumeData.count >= VolumeData.max)
  177.         return 1;
  178.     (VolumeData.base)[VolumeData.count] = adr;
  179.     VolumeData.count++;
  180.     return 0;
  181. }
  182.  
  183. /* ----- Return length of info record ---------------------------------- */
  184.  
  185. static unsigned long Length (register FileInfoPtr p)
  186. {
  187.     register unsigned long length;
  188.  
  189.     length = sizeof(FileInfo) + p->name[0] + 1;
  190.     if (length & 1)
  191.         ++length;        /* Make it even */
  192.     return length;
  193. }
  194.  
  195. /* ----- Return next info record --------------------------------------- */
  196.  
  197. static FileInfoPtr NextRecord (register FileInfoPtr record)
  198. {
  199.     return (FileInfoPtr)((Ptr)record + Length(record));
  200. }
  201.  
  202. /* ----- Accept new info record ---------------------------------------- */
  203.  
  204. static long NewInfo (
  205.     short kind,
  206.     unsigned long parent,
  207.     unsigned long volume,
  208.     Ptr name,
  209.     unsigned long size,
  210.     unsigned long cdate,
  211.     unsigned long mdate,
  212.     unsigned long x,
  213.     unsigned long y)
  214. {
  215.     register FileInfoPtr p;
  216.     register unsigned long length;
  217.     register unsigned long adr;
  218.     register unsigned short namelength;
  219.  
  220.     namelength = name[0];
  221.     if (namelength >= sizeof(FILENAME))
  222.         namelength = sizeof(FILENAME) - 1;
  223.     length = sizeof(FileInfo) + namelength + 1;
  224.     if (length & 1)
  225.         ++length;        /* Make it even */
  226.     if (InfoSize + length > InfoMax)
  227.         return NOTHING;
  228.     p = (FileInfoPtr)(InfoBase + InfoSize);
  229.     p->kind = kind;
  230.     p->parent = parent;
  231.     p->volume = volume;
  232.     p->size = size;
  233.     p->cdate = cdate;
  234.     p->mdate = mdate;
  235.     p->type = x;
  236.     p->creator = y;
  237.     p->name[0] = namelength;
  238.     BlockMove(name + 1, p->name + 1, namelength);
  239.     adr = InfoSize;
  240.     InfoSize += length;
  241.     ++InfoCount;
  242.     return adr;
  243. }
  244.  
  245. /* ----- Find volume by name ------------------------------------------- */
  246.  
  247. Boolean FindVolume (
  248.     register Byte *name,
  249.     unsigned long *index)
  250. {
  251.     register unsigned long v;
  252.     register FileInfoPtr p;
  253.  
  254.     for (v = 0; v < VolumeData.count; v++) {
  255.         p = Address(&VolumeData, v);
  256.         if (StrCompare(name, p->name) == 0) {
  257.             *index = v;
  258.             return TRUE;
  259.         }
  260.     }
  261.     return FALSE;
  262. }
  263.  
  264. /* ----- Unmount/eject volume ------------------------------------------ */
  265.  
  266. void KillVolume (register HVolumeParam *VolPB)
  267. {
  268.     register short vol, drive, err;
  269.  
  270.     /* Do not eject system volume or application volume */
  271.     if (!(vol = VolPB->ioVRefNum) || vol == SysVol || vol == ApplVol)
  272.         return;
  273.     drive = VolPB->ioVDrvInfo;    /* Drive number */
  274.  
  275.     FillMemory((Byte *)VolPB, sizeof(HVolumeParam), 0);
  276.     VolPB->ioVRefNum = vol;
  277.     err = PBUnmountVol(VolPB);
  278.  
  279.     FillMemory((Byte *)VolPB, sizeof(HVolumeParam), 0);
  280.     VolPB->ioVRefNum = drive;
  281.     err = PBEject(VolPB);
  282.  
  283. /*
  284.     if (err)
  285.         Message(ERR_DISK, err);
  286. */
  287. }
  288.  
  289. /* ----- Clear index tables -------------------------------------------- */
  290.  
  291. static void ClearIndexTables (void)
  292. {
  293.     register Ptr p, q, himem;
  294.  
  295.     FileData.count = VolumeData.count = 0;
  296.     p = q = InfoBase;
  297.     himem = p + InfoSize;
  298.     while(q < himem) {
  299.         switch (((FileInfoPtr)q)->kind) {
  300.             case VOLUME:
  301.                 NewVolume(q - p);
  302.                 break;
  303.             case FILE:
  304.                 NewFile(q - p);
  305.                 break;
  306.         }
  307.         q += Length((FileInfoPtr)q);
  308.     }
  309. }
  310.  
  311. /* ----- No sort ------------------------------------------------------- */
  312.  
  313. void NoSort (void)
  314. {
  315.     if (FileData.select != -1L)
  316.         Select(&FileData, FileData.select, FALSE);
  317.     if (VolumeData.select != -1L)
  318.         Select(&VolumeData, VolumeData.select, FALSE);
  319.     ClearIndexTables();
  320.     Update();
  321.     ClearSorted(&FileData);
  322.     ClearSorted(&VolumeData);
  323.     Dirty = TRUE;
  324. }
  325.  
  326. /* ----- Rename a volume ----------------------------------------------- */
  327.  
  328. static void AdjustInfoRecords (
  329.     register FileInfoPtr p,        /* First record to adjust */
  330.     register Ptr max,            /* Record limit */
  331.     register long x,            /* Highest valid index */
  332.     register long offset)        /* Reference offset */
  333. {
  334.     while ((Ptr)p < max) {
  335.         if (p->kind != VOLUME) {
  336.             if (p->parent > x)
  337.                 p->parent += offset;
  338.             if (p->volume > x)
  339.                 p->volume += offset;
  340.         }
  341.         p = NextRecord(p);
  342.     }
  343. }
  344.  
  345. #ifdef ADJUSTINDEX
  346. static void AdjustIndexTable (
  347.     register long *base,        /* Index table base */
  348.     register long *max,            /* Index table limit */
  349.     register long x,            /* Highest valid index */
  350.     register long offset)        /* Reference offset */
  351. {
  352.     while (base < max) {
  353.         if (*base > x)
  354.             *base += offset;
  355.         ++base;
  356.     }
  357. }
  358. #endif
  359.  
  360. static short NewVolumeName (
  361.     register FileInfoPtr volume,    /* Volume to rename */
  362.     Byte *newname)                    /* New volume name */
  363. {
  364.     register FileInfoPtr record;
  365.     register long delta, x;
  366.  
  367.     /* Record length difference */
  368.  
  369.     delta = sizeof(FileInfo) + newname[0] + 1;
  370.     if (delta & 1)
  371.         ++delta;    /* Make it even */
  372.     delta -= Length(volume);
  373.     if ((InfoSize + delta) > InfoMax)
  374.         return 1;    /* Error */
  375.  
  376.     /* Move all higher records then copy the new name */
  377.  
  378.     record = NextRecord(volume);
  379.     if (delta && (x = InfoBase + InfoSize - (Ptr)record))
  380.         BlockMove((Ptr)record, (Ptr)record + delta, x);
  381.     BlockMove(newname, volume->name, *newname + 1);
  382.     InfoSize += delta;
  383.  
  384.     /* Ajust all parent and volume references in info records 
  385.     and in index tables. */
  386.  
  387.     if (delta) {
  388.         x = (Ptr)volume - InfoBase;
  389.         AdjustInfoRecords(NextRecord(volume), InfoBase + InfoSize,
  390.             x, delta);
  391. #ifdef ADJUSTINDEX
  392.         AdjustIndexTable(VolumeData.base, VolumeData.base +
  393.             VolumeData.count, x, delta);
  394.         AdjustIndexTable(FileData.base, FileData.base + FileData.count,
  395.             x, delta);
  396. #else
  397.         ClearIndexTables();
  398. #endif
  399.     }
  400.  
  401.     return 0;    /* Ok */
  402. }
  403.  
  404. /* ----- Clear selections ---------------------------------------------- */
  405.  
  406. static void ClearSelection (register WindowDataPtr w)
  407. {
  408.     if (w->select != NOTHING) {
  409.         SetPort(w);
  410.         ToggleIt(w, w->select);
  411.     }
  412. }
  413.  
  414. static void ClearSelections (void)
  415. {
  416.     ClearSelection(&FileData);
  417.     ClearSelection(&VolumeData);
  418. }
  419.  
  420. /* ----- Select volume dialog ------------------------------------------ */
  421.  
  422. void AddVolumes (void)
  423. {
  424.     register HVolumeParam *VolPB;
  425.     register short err;
  426.     register short i, n, v;
  427.     register DialogPtr dialog;
  428.     short volumes[SelectCount];
  429.     short check[SelectCount];
  430.     Boolean eject;
  431.     short item;
  432.     Byte s[256];
  433.  
  434.     CenterDialog('DLOG', SelectDialog);
  435.     if (!(dialog = GetNewDialog(SelectDialog, 0, -1)))
  436.         return;
  437.     SetWatch();
  438.     FileSearchOpen(0);
  439.     FirstVol(0);
  440.     for (i = 0; i < SelectCount; i++) {
  441.         VolPB = NextVol();
  442.         if (VolPB->ioResult)
  443.                 break;
  444.         volumes[i] = VolPB->ioVRefNum;
  445.         check[i] = FALSE;
  446.         /*
  447.         NumToString((long)(VolPB->ioVRefNum), s);
  448.         if (VolPB->ioVRefNum == SysVol)
  449.             Append(s, "\p/SYS");
  450.         if (VolPB->ioVRefNum == ApplVol)
  451.             Append(s, "\p/APP");
  452.         Append(s, "\p/");
  453.         Append(s, VolPB->ioNamePtr);
  454.         ControlName(dialog, i+SelectVolume, s);
  455.         */
  456.         ControlName(dialog, i+SelectVolume, VolPB->ioNamePtr);
  457.     }
  458.     n = i;
  459.     FileSearchClose();
  460.     for (i = n; i < SelectCount; i++) {
  461.         volumes[i] = 0;
  462.         check[i] = FALSE;
  463.         ControlName(dialog, i+SelectVolume, EmptyStr);
  464.     }
  465.     eject = 0;
  466.     ShowWindow(dialog);
  467.     InitCursor();
  468.     while (TRUE) {
  469.         ModalDialog(0L, &item);
  470.         if (item < SelectVolume)
  471.             break;
  472.         ControlToggle(dialog, item);
  473.     }
  474.     if (item == SelectOk) {
  475.         for (i = 0; i < n; ++i)
  476.             check[i] = ControlCheck(dialog, i + SelectVolume);
  477.         eject = ControlCheck(dialog, SelectEject);
  478.     }
  479.     DisposDialog(dialog);
  480.     if (item == SelectOk) {
  481.         for (i = v = 0; i < n; i++)
  482.             if (check[i]) {
  483.                 v++;
  484.                 if (err = SearchVol(volumes[i], eject)) {
  485.                     Message(err, 0);
  486.                     break;
  487.                 }
  488.             }
  489.         if (v) {
  490.             Update();
  491.             ClearSorted(&FileData);
  492.             ClearSorted(&VolumeData);
  493.             Dirty = TRUE;
  494.         }
  495.     }
  496.     InitCursor();
  497.     return;
  498. }
  499.  
  500. /* ----- Delete a volume ----------------------------------------------- */
  501.  
  502. static void CutVolume (long v)
  503. {
  504.     register FileInfoPtr q, himem, x, p;
  505.     register long lost;
  506.  
  507.     SetWatch();
  508.     ClearSelections();
  509.  
  510.     p = q = Address(&VolumeData, v);
  511.     himem = (FileInfoPtr)(InfoBase + InfoSize);
  512.     do {
  513.         --InfoCount;
  514.         q = NextRecord(q);
  515.     } while(q < himem && q->kind != VOLUME);
  516.     lost = (Ptr)q - (Ptr)p;
  517.     if (q < himem) {
  518.         x = q;
  519.         do {
  520.             if (x->kind != VOLUME) {
  521.                 x->parent -= lost;
  522.                 x->volume -= lost;
  523.             }
  524.             x = NextRecord(x);
  525.         } while(x < himem);
  526.         BlockMove(q, p, (Ptr)himem - (Ptr)q);
  527.     }
  528.     InfoSize -= lost;
  529.     ClearIndexTables();
  530.  
  531.     Dirty = (InfoSize) ? TRUE : FALSE;
  532.     Update();
  533.     ClearSorted(&FileData);
  534.     ClearSorted(&VolumeData);
  535.     InitCursor();
  536. }
  537.  
  538. /* ----- Delete selected volume ---------------------------------------- */
  539.  
  540. void DeleteVolume (void)
  541. {
  542.     register FileInfoPtr p;
  543.     register long x = VolumeData.select;
  544.  
  545.     if (x == NOTHING)
  546.         return;
  547.     p = Address(&VolumeData, x);
  548.     ParamText(p->name, EmptyStr, EmptyStr, EmptyStr);
  549.     CenterDialog('ALRT', DeleteDialog);
  550.     if (CautionAlert(DeleteDialog, 0) != DeleteOk)
  551.         return;
  552.     CutVolume(x);
  553. }
  554.  
  555. /* ----- Rename volume dialog ------------------------------------------ */
  556.  
  557. static short RenameVol (
  558.     register Byte *oldname,
  559.     register Byte *name,
  560.     Boolean replace)
  561. {
  562.     register DialogPtr dialog;
  563.     register Boolean cont = TRUE;
  564.     register short result = 1;
  565.     short item;
  566.     unsigned long index;
  567.  
  568.     CenterDialog('DLOG', RenameDialog);
  569.     if (!(dialog = GetNewDialog(RenameDialog, 0, -1)))
  570.         return result;
  571.     ShowHideControl(dialog, RenameRepl, replace);
  572.     setText(dialog, RenameOld, oldname);
  573.     setText(dialog, RenameNew, oldname);
  574.     SelIText(dialog, RenameNew, 0, 0x7FFF);
  575.     do {
  576.         ModalDialog(0, &item);
  577.         switch(item) {
  578.             case RenameOk:
  579.                 getText(dialog, RenameNew, name);
  580.                 /* Make sure name is not too long and is unique */
  581.                 if (*name > (sizeof(VOLNAME) - 1) ||
  582.                         FindVolume(name, &index)) {
  583.                     SysBeep(1);
  584.                     break;
  585.                 }
  586.                 result = 0;
  587.                 /* Fall thru */
  588.             case RenameNo:
  589.                 cont = FALSE;
  590.                 break;
  591.             case RenameRepl:
  592.                 if (FindVolume(oldname, &index))
  593.                     CutVolume(index);
  594.                 result = 0;
  595.                 cont = FALSE;
  596.                 break;
  597.         }
  598.     } while(cont);
  599.     DisposDialog(dialog);
  600.     return result;
  601. }
  602.  
  603. /* ----- Rename selected volume ---------------------------------------- */
  604.  
  605. void RenameVolume (void)
  606. {
  607.     register FileInfoPtr p;
  608.     register long x = VolumeData.select;
  609.     register Byte name[256];
  610.  
  611.     if (x == NOTHING)
  612.         return;
  613.     p = Address(&VolumeData, x);
  614.     if (RenameVol(p->name, name, FALSE))
  615.         return;
  616.     ClearSelections();
  617.     NewVolumeName(p, name);
  618.     Dirty = TRUE;
  619.     Update();
  620.     ClearSorted(&FileData);
  621.     ClearSorted(&VolumeData);
  622. }
  623.  
  624. /* ----- Search all files on volume ------------------------------------ */
  625.  
  626. #define AccessDenied -5000    /* If cataloging a file server volume */
  627.  
  628. short SearchVol (short drive, Boolean eject)
  629. {
  630.     register HVolumeParam *VolPB;
  631.     register CInfoPBPtr FilePB;
  632.     register err;
  633.     register unsigned long dir, fil, vol;
  634.     unsigned long index;
  635.     STACK stack;
  636.     short archive = 0;
  637.     char name[256];
  638.     unsigned long files = 0;    /* Files on volume */
  639.  
  640.     FileSearchOpen(0);            /* Initialize file search */
  641.     err = ERR_DISK;
  642.     InitStack(&stack);
  643.     VolPB = FirstVol(drive);
  644.     if (VolPB->ioResult)
  645.         goto done2;
  646.     *name = 0;
  647.     /* If volume name exists, try to rename the new volume,
  648.     or replace the old volume. */
  649.     if (FindVolume(VolPB->ioNamePtr, &index) &&
  650.             RenameVol((Byte *)VolPB->ioNamePtr, (Byte *)name, TRUE))
  651.         goto done0;
  652.     SetWatch();
  653.     err = ERR_MEMORY;
  654.     fil = VolPB->ioVAlBlkSiz;
  655.     if ((dir = NewInfo(
  656.             VOLUME,                                    /* Kind */
  657.             NOTHING,                                /* Parent pointer */
  658.             NOTHING,                                /* Volume pointer */
  659.             *name ? name : (Ptr)VolPB->ioNamePtr,    /* Name */
  660.             int2long(VolPB->ioVNmAlBlks) * fil,        /* Total size */
  661.             VolPB->ioVCrDate,                        /* Creation date */
  662.             VolPB->ioVLsMod,                        /* Modification date */
  663.             int2long(VolPB->ioVFrBlk) * fil,        /* Free space */
  664.             VolPB->ioVFilCnt)) == NOTHING)            /* Files */
  665.         goto done1;
  666.     if (NewVolume(dir))
  667.         goto done1;
  668.     vol = dir;
  669.     FirstFile(0);                /* Initialize search thru all files */
  670.     while (TRUE) {
  671.         if (archive) {    /* Reading from archive? */
  672.             FilePB = NextArchiveFile();
  673.             if (FilePB->hFileInfo.ioResult == eofErr) {    /* End of archive */
  674.                 CloseArchive();
  675.                 archive = 0;
  676.                 if ((dir = PopStack(&stack)) == STACKERROR)
  677.                     goto done1;
  678.                 continue;
  679.             }
  680.             if (FilePB->hFileInfo.ioResult == fnfErr) {    /* End of folder */
  681.                 if ((dir = PopStack(&stack)) == STACKERROR)
  682.                     goto done1;
  683.                 continue;
  684.             } else {
  685.                 if (FilePB->hFileInfo.ioResult) {
  686.                     err = ERR_DISK;
  687.                     goto done1;
  688.                 }
  689.             }
  690.         } else {        /* Not reading from archive */
  691.             FilePB = NextFile();
  692.             if (FilePB->hFileInfo.ioResult == fnfErr ||
  693.                     FilePB->hFileInfo.ioResult == dirNFErr)    /* not found */
  694.                 if (PopDir()) {                        /* Pop up a level */
  695.                     if ((dir = PopStack(&stack)) == STACKERROR)
  696.                         goto done1;
  697.                     continue;
  698.                 } else                                /* ...if any */
  699.                     break;    /* Normal loop exit */
  700.             else {
  701.                 if (FilePB->hFileInfo.ioResult == AccessDenied)
  702.                     continue;
  703.                 if (FilePB->hFileInfo.ioResult) {
  704.                     err = ERR_DISK;
  705.                     goto done1;
  706.                 }
  707.             }
  708.         }
  709.         if (FilePB->hFileInfo.ioFlAttrib & 0x10) {    /* Directory */
  710.             if ((fil = NewInfo(
  711.                     FOLDER,                            /* Kind */
  712.                     dir,                            /* Parent pointer */
  713.                     vol,                            /* Volume pointer */
  714.                     (Ptr)FilePB->dirInfo.ioNamePtr,    /* Name */
  715.                     0,
  716.                     FilePB->dirInfo.ioDrCrDat,        /* Creation date */
  717.                     FilePB->dirInfo.ioDrMdDat,        /* Modification date */
  718.                     0,
  719.                     (long)FilePB->dirInfo.ioDrNmFls)) == NOTHING)
  720.                 goto done1;
  721.             if (!PushStack(&stack, dir))
  722.                 goto done1;
  723.             dir = fil;
  724.             if (!archive)
  725.                 FirstFile(FilePB->dirInfo.ioDrDirID);
  726.         } else {                                    /* File */
  727.             if (!archive &&
  728.                     (archive = IsArchive(&FilePB->hFileInfo))) {
  729.                 if ((fil = NewInfo(
  730.                         FOLDER,                        /* Kind */
  731.                         dir,                        /* Parent pointer */
  732.                         vol,                        /* Volume pointer */
  733.                         (Ptr)FilePB->dirInfo.ioNamePtr,    /* Name */
  734.                         0,
  735.                         FilePB->dirInfo.ioDrCrDat,    /* Creation date */
  736.                         FilePB->dirInfo.ioDrMdDat,    /* Modification date */
  737.                         0,
  738.                         (long)FilePB->dirInfo.ioDrNmFls)) == NOTHING)
  739.                     goto done1;
  740.                 if (!PushStack(&stack, dir))
  741.                     goto done1;
  742.                 dir = fil;
  743.             } else {
  744.                 if ((fil = NewInfo(
  745.                         FILE,                            /* Kind */
  746.                         dir,                            /* Parent */
  747.                         vol,                            /* Volume ptr */
  748.                         (Ptr)FilePB->hFileInfo.ioNamePtr,    /* Name */
  749.                         FilePB->hFileInfo.ioFlLgLen +
  750.                             FilePB->hFileInfo.ioFlRLgLen,    /* Size */
  751.                         FilePB->hFileInfo.ioFlCrDat,    /* Creation date */
  752.                         FilePB->hFileInfo.ioFlMdDat,    /* Modif. date */
  753.                         FilePB->hFileInfo.ioFlFndrInfo.fdType,
  754.                         FilePB->hFileInfo.ioFlFndrInfo.fdCreator))
  755.                         == NOTHING)
  756.                     goto done1;
  757.                 ++files;    /* One more file in volume */
  758.                 if (NewFile(fil))
  759.                     goto done1;
  760.             }
  761.         }
  762.     }
  763.     /* Set correct file count */
  764.     ((FileInfoPtr)(InfoBase + vol))->creator = files;
  765. done0:
  766.     err = 0;
  767. done1:
  768.     if (archive)
  769.         CloseArchive();
  770.     if (eject)
  771.         KillVolume(VolPB);
  772. done2:
  773.     FileSearchClose();
  774.     InitCursor();
  775.     return err;
  776. }
  777.  
  778. /* ----- Find again ---------------------------------------------------- */
  779.  
  780. void Again (void)
  781. {
  782.     register WindowDataPtr w = (WindowDataPtr)FrontWindow();
  783.     register unsigned long v;
  784.     register unsigned long x;
  785.     register FileInfoPtr p;
  786.     register short y1, y2;
  787.     Rect r;
  788.  
  789.     SetWatch();
  790.     SetPort(w);
  791.     ToggleIt(w, x = w->select);
  792.     for (v = x + 1; v < w->count; v++) {
  793.         p = Address(w, v);
  794.         if ((!w->find[0] || (*w->match)(w->find, p->name)) &&
  795.                 (!w->type || (w->type == p->type)) &&
  796.                 (!w->creator || (w->creator == p->creator))) {
  797.             y1 = GetCtlValue(w->vs);
  798.             ContentRect((WindowPtr)w, &r);
  799.             y2 = y1 + (r.bottom - r.top)/w->height;
  800.             if (v < y1 || v >= y2) {
  801.                 SetCtlValue(w->vs, v - (y2 - y1)/2);
  802.                 InvalRect(&r);
  803.             }
  804.             ToggleIt(w, v);
  805.             goto done;
  806.         }
  807.     }
  808.     SysBeep(1);    /* Nothing found */
  809. done:
  810.     InitCursor();
  811. }
  812.  
  813. /* ----- Find dialog --------------------------------------------------- */
  814.  
  815. static void L2S (unsigned long x, register Byte *s)
  816. {
  817.     *s++ = sizeof(unsigned long);
  818.     BlockMove(&x, s, sizeof(unsigned long));
  819.     printable(s, sizeof(unsigned long));
  820. }
  821.  
  822. static unsigned long S2L (Byte *s)
  823. {
  824.     unsigned long x = '    ';
  825.  
  826.     BlockMove(s + 1, &x, *s);
  827.     return x;
  828. }
  829.  
  830. typedef Boolean (*MP)();
  831.  
  832. void Find (void)
  833. {
  834.     register WindowDataPtr w = (WindowDataPtr)FrontWindow();
  835.     register DialogPtr dialog;
  836.     register Boolean cont = TRUE;
  837.     register Byte name[256];
  838.     register short i;
  839.     register Byte s[256];
  840.     unsigned long type, creator;
  841.     Boolean ff;
  842.     short item;
  843.     static MP m[] = { StrEquals, StrBegins, StrIncludes, StrEnds };
  844.     unsigned long x;
  845.  
  846.     SetPort(w);
  847.     ToggleIt(w, x = w->select);
  848.     if (w == &FileData) {
  849.         ff = TRUE;
  850.         i = FindDialogF;
  851.     } else {
  852.         ff = FALSE;
  853.         i = FindDialogV;
  854.     }
  855.     CenterDialog('DLOG', i);
  856.     if (!(dialog = GetNewDialog(i, 0L, -1L)))
  857.         return;
  858.     setText(dialog, FindStr, w->find);
  859.     SelIText(dialog, FindStr, 0, 0x7FFF);
  860.     if (ff) {
  861.         if (w->type)
  862.             L2S(w->type, s);
  863.         else
  864.             *s = 0;
  865.         setText(dialog, FindType, s);
  866.         if (w->creator)
  867.             L2S(w->creator, s);
  868.         else
  869.             *s = 0;
  870.         setText(dialog, FindCreator, s);
  871.     }
  872.     for (i = 0; i < 4; ++i)
  873.         if (m[i] == w->match) {
  874.             SetRadioButton(dialog, FindEqual, FindEnd, FindEqual + i);
  875.             break;
  876.         }
  877.     do {
  878.         ModalDialog(0L, &item);
  879.         switch(item) {
  880.             case FindOk:
  881.                 getText(dialog, FindStr, name);
  882.                 if (*name > (sizeof(w->find) - 1)) {
  883.                     SysBeep(1);
  884.                     break;
  885.                 }
  886.                 if (ff) {
  887.                     getText(dialog, FindType, s);
  888.                     if (*s > sizeof(unsigned long)) {
  889.                         SysBeep(1);
  890.                         break;
  891.                     }
  892.                     type = *s ? S2L(s) : 0;
  893.                     getText(dialog, FindCreator, s);
  894.                     if (*s > sizeof(unsigned long)) {
  895.                         SysBeep(1);
  896.                         break;
  897.                     }
  898.                     creator = *s ? S2L(s) : 0;
  899.                 }
  900.                 i = GetRadioButton(dialog, FindEqual, FindEnd) - FindEqual;
  901.             case FindNo:
  902.                 cont = FALSE;
  903.                 break;
  904.             case FindEqual:
  905.             case FindBegin:
  906.             case FindInclude:
  907.             case FindEnd:
  908.                 SetRadioButton(dialog, FindEqual, FindEnd, item);
  909.                 break;
  910.         }
  911.     } while(cont);
  912.     DisposDialog(dialog);
  913.     SetPort(w);
  914.     ToggleIt(w, x);
  915.     if (item == FindOk) {
  916.         BlockMove(name, w->find, *name + 1);
  917.         if (ff) {
  918.             w->type = type;
  919.             w->creator = creator;
  920.         }
  921.         w->match = m[i];
  922.         Again();
  923.     }
  924. }
  925.